﻿using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Docx2Epub.Docx
{
    public class ElementTraverser
    {
        private IEnumerable<OpenXmlElement> elements;

        public ElementTraverser(IEnumerable<OpenXmlElement> elements)
        {
            this.elements = elements;
        }

        public IEnumerable<DocElement> TraverseDocTree()
        {
            var results = new List<DocElement>();
            var currSecNum = new List<int>();

            // index of this list equals section level
            // there is no section/chapter having level = 0 so add -1
            currSecNum.Add(-1);
            // initial chapter index
            currSecNum.Add(0);

            foreach (var e in elements)
            {
                var paragraph = e as Paragraph;
                if (paragraph == null)
                    continue;

                int lvl = getLevel(paragraph);
                if (lvl == 0)
                    results.Add(new DocParagraph(paragraph));
                else if (lvl == 1)
                    results.Add(new DocChapter(paragraph.InnerText, ++currSecNum[lvl]));
                else if (lvl == currSecNum.Count - 1)
                {
                    // level not changed
                    currSecNum[lvl]++;
                    results.Add(new DocSection(paragraph.InnerText, lvl, currSecNum.Skip(1)));
                }
                else if (lvl > currSecNum.Count - 1)
                {
                    // level up
                    currSecNum.Add(1);
                    results.Add(new DocSection(paragraph.InnerText, lvl, currSecNum.Skip(1)));
                }
                else if (lvl < currSecNum.Count - 1)
                {
                    // level down
                    currSecNum.RemoveAt(currSecNum.Count - 1);
                    currSecNum[lvl]++;
                    results.Add(new DocSection(paragraph.InnerText, lvl, currSecNum.Skip(1)));
                }
                else
                    Debug.Fail("no such case");
            }
            return results;
        }

        private int getLevel(Paragraph p)
        {
            var properties = p.Elements<ParagraphProperties>().ToList();
            if (properties.Count == 0)
                return 0;

            var prop = properties.First();

            if (prop.NumberingProperties != null &&
                prop.NumberingProperties.NumberingLevelReference != null)
                return prop.NumberingProperties.NumberingLevelReference.Val + 1;
            else
                return 0;
        }

    }
}
